package com.jeecg.p3.qrcode.util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
public class ExcelUtil {
	/** 
	 *  
	 * @param title     Sheet名字 
	 * @param pojoClass Excel对象Class 
	 * @param dataSet   Excel对象数据List 
	 * @param out       输出流 
	 */  
	private static void exportExcel(String title, Class<?> pojoClass,  
	        Collection<?> dataSet, OutputStream out) {  
	    // 使用userModel模式实现的，当excel文档出现10万级别的大数据文件可能导致OOM内存溢出  
	    exportExcelInUserModel(title, pojoClass, dataSet, out);  
	    // 使用eventModel实现，可以一边读一边处理，效率较高，但是实现复杂，暂时未实现  
	}  
	  
	private static void exportExcelInUserModel(String title, Class<?> pojoClass,  
	        Collection<?> dataSet, OutputStream out) {
	    try {  
	        // 首先检查数据看是否是正确的  
	    	//update-begin-Alex---Date:20180910---for:修改逻辑，数据为空时可导出表头------
	        if (dataSet == null) {  
	        //update-end-Alex---Date:20180910---for:修改逻辑，数据为空时可导出表头------
	            throw new Exception("导出数据为空！");  
	        }  
	        if (title == null || out == null || pojoClass == null) {  
	            throw new Exception("传入参数不能为空！");  
	        }  
	        // 声明一个工作薄  
	        Workbook workbook = new HSSFWorkbook();  
	        // 生成一个表格  
	        Sheet sheet = workbook.createSheet(title);  
	  
	        // 标题  
	        List<String> exportFieldTitle = new ArrayList<String>();  
	        List<Integer> exportFieldWidth = new ArrayList<Integer>();  
	        // 拿到所有列名，以及导出的字段的get方法  
	        List<Method> methodObj = new ArrayList<Method>();  
	        Map<String, Method> convertMethod = new HashMap<String, Method>();  
	        // 得到所有字段  
	        Field fileds[] = pojoClass.getDeclaredFields();  
	        // 遍历整个filed  
	        for (int i = 0; i < fileds.length; i++) {  
	            Field field = fileds[i];  
	            Excel excel = field.getAnnotation(Excel.class);  
	            // 如果设置了annottion  
	            if (excel != null) {  
	                // 添加到标题  
	                exportFieldTitle.add(excel.exportName());  
	                // 添加标题的列宽  
	                exportFieldWidth.add(excel.exportFieldWidth());  
	                // 添加到需要导出的字段的方法  
	                String fieldname = field.getName();  
	                // System.out.println(i+"列宽"+excel.exportName()+" "+excel.exportFieldWidth());  
	                StringBuffer getMethodName = new StringBuffer("get");  
	                getMethodName.append(fieldname.substring(0, 1)  
	                        .toUpperCase());  
	                getMethodName.append(fieldname.substring(1));  
	  
	                Method getMethod = pojoClass.getMethod(getMethodName  
	                        .toString(), new Class[] {});  
	  
	                methodObj.add(getMethod);  
	                if (excel.exportConvertSign() == 1) {  
	                    StringBuffer getConvertMethodName = new StringBuffer(  
	                            "get");  
	                    getConvertMethodName.append(fieldname.substring(0, 1)  
	                            .toUpperCase());  
	                    getConvertMethodName.append(fieldname.substring(1));  
	                    getConvertMethodName.append("Convert");  
	                    // System.out.println("convert: "+getConvertMethodName.toString());  
	                    Method getConvertMethod = pojoClass  
	                            .getMethod(getConvertMethodName.toString(),  
	                                    new Class[] {});  
	                    convertMethod.put(getMethodName.toString(),  
	                            getConvertMethod);  
	                }  
	            }  
	        }  
	        int index = 0;  
	        // 产生表格标题行  
	        Row row = sheet.createRow(index);  
	        for (int i = 0, exportFieldTitleSize = exportFieldTitle.size(); i < exportFieldTitleSize; i++) {  
	            Cell cell = row.createCell(i);  
	            // cell.setCellStyle(style);  
	            RichTextString text = new HSSFRichTextString(exportFieldTitle  
	                    .get(i));  
	            cell.setCellValue(text);  
	        }  
	  
	        // 设置每行的列宽  
	        for (int i = 0; i < exportFieldWidth.size(); i++) {  
	            // 256=65280/255  
	            sheet.setColumnWidth(i, 256 * exportFieldWidth.get(i));  
	        }  
	        @SuppressWarnings("rawtypes")
			Iterator its = dataSet.iterator();  
	        // 循环插入剩下的集合  
	        while (its.hasNext()) {  
	            // 从第二行开始写，第一行是标题  
	            index++;  
	            row = sheet.createRow(index);  
	            Object t = its.next();  
	            for (int k = 0, methodObjSize = methodObj.size(); k < methodObjSize; k++) {  
	                Cell cell = row.createCell(k);  
	                Method getMethod = methodObj.get(k);  
	                Object value = null;  
	                if (convertMethod.containsKey(getMethod.getName())) {  
	                    Method cm = convertMethod.get(getMethod.getName());  
	                    value = cm.invoke(t, new Object[] {});  
	                } else {  
	                    value = getMethod.invoke(t, new Object[] {});  
	                }  
	                cell.setCellValue(value == null ? "" : value.toString());  
	            }  
	        }  
	  
	        workbook.write(out);  
	    } catch (Exception e) {  
	        e.printStackTrace();  
	    }  
	  
	}  

	/**
	 * 导入 excel
	 * 
	 * @param file
	 * @param pojoClass
	 * @param pattern
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static Collection importExcel(File file, Class pojoClass) {
		Collection dist = new ArrayList<Object>();
		try {
			// 得到目标目标类的所有的字段列表
			Field filed[] = pojoClass.getDeclaredFields();
			// 将所有标有Annotation的字段，也就是允许导入数据的字段,放入到一个map中
			Map<String, Method> fieldSetMap = new HashMap<String, Method>();
			Map<String, Method> fieldSetConvertMap = new HashMap<String, Method>();
			// 循环读取所有字段
			for (int i = 0; i < filed.length; i++) {
				Field f = filed[i];
				// 得到单个字段上的Annotation
				Excel excel = f.getAnnotation(Excel.class);
				// 如果标识了Annotationd的话
				if (excel != null) {
					// 构造设置了Annotation的字段的Setter方法
					String fieldname = f.getName();
					String setMethodName = "set" + fieldname.substring(0, 1).toUpperCase() + fieldname.substring(1);
					// 构造调用的method，
					Method setMethod = pojoClass.getMethod(setMethodName, new Class[] { f.getType() });
					// 将这个method以Annotaion的名字为key来存入。
					// 对于重名将导致 覆盖 失败，对于此处的限制需要
					fieldSetMap.put(excel.exportName(), setMethod);
					if (excel.importConvertSign() == 1) {
						StringBuffer setConvertMethodName = new StringBuffer("set");
						setConvertMethodName.append(fieldname.substring(0, 1).toUpperCase());
						setConvertMethodName.append(fieldname.substring(1));
						setConvertMethodName.append("Convert");
						Method getConvertMethod = pojoClass.getMethod(setConvertMethodName.toString(), new Class[] { String.class });
						fieldSetConvertMap.put(excel.exportName(), getConvertMethod);
					}
				}
			}
			// 将传入的File构造为FileInputStream;
			FileInputStream in = new FileInputStream(file);
			// // 得到工作表
			HSSFWorkbook book = new HSSFWorkbook(in);
			// // 得到第一页
			HSSFSheet sheet = book.getSheetAt(0);
			// // 得到第一面的所有行
			Iterator<Row> row = sheet.rowIterator();
			// 得到第一行，也就是标题行
			Row title = row.next();
			// 得到第一行的所有列
			Iterator<Cell> cellTitle = title.cellIterator();
			// 将标题的文字内容放入到一个map中。
			Map titlemap = new HashMap();
			// 从标题第一列开始
			int i = 0;
			// 循环标题所有的列
			while (cellTitle.hasNext()) {
				Cell cell = cellTitle.next();
				String value = cell.getStringCellValue();
				titlemap.put(i, value);
				i = i + 1;
			}
			// 用来格式化日期的DateFormat
			@SuppressWarnings("unused")
			SimpleDateFormat sf;
			while (row.hasNext()) {
				// 标题下的第一行
				Row rown = row.next();
				// 行的所有列
				Iterator<Cell> cellbody = rown.cellIterator();
				// 得到传入类的实例
				Object tObject = pojoClass.newInstance();
				// 遍历一行的列
				while (cellbody.hasNext()) {
					Cell cell = cellbody.next();
					// 这里得到此列的对应的标题
					String titleString = (String) titlemap.get(cell.getColumnIndex());
					// 如果这一列的标题和类中的某一列的Annotation相同，那么则调用此类的的set方法，进行设值
					if (fieldSetMap.containsKey(titleString)) {
						Method setMethod = (Method) fieldSetMap.get(titleString);
						// 得到setter方法的参数
						Type[] ts = setMethod.getGenericParameterTypes();
						// 只要一个参数
						String xclass = ts[0].toString();
						// 判断参数类型
						if (fieldSetConvertMap.containsKey(titleString)) {
							cell.setCellType(Cell.CELL_TYPE_STRING);
							fieldSetConvertMap.get(titleString).invoke(tObject, cell.getStringCellValue());
						} else {
							if (xclass.equals("class java.lang.String")) {
								// 先设置Cell的类型，然后就可以把纯数字作为String类型读进来了：
								cell.setCellType(Cell.CELL_TYPE_STRING);
								setMethod.invoke(tObject, cell.getStringCellValue());
							} else if (xclass.equals("class java.util.Date")) {
								try {
									setMethod.invoke(tObject, cell.getDateCellValue());
								} catch (Exception e) {
								}
							} else if (xclass.equals("class java.lang.Boolean")) {
								setMethod.invoke(tObject, cell.getBooleanCellValue());
							} else if (xclass.equals("class java.lang.Integer")) {
								Double numericCellValue = cell.getNumericCellValue();
								if (numericCellValue != null) {
									setMethod.invoke(tObject, numericCellValue.intValue());
								}
							} else if (xclass.equals("class java.lang.Long")) {
								setMethod.invoke(tObject, new Long(cell.getStringCellValue()));
							} else if (xclass.equals("class java.math.BigDecimal")) {
								// 先设置Cell的类型，然后就可以把纯数字作为String类型读进来了
								cell.setCellType(Cell.CELL_TYPE_STRING);
								String numericCell=cell.getStringCellValue();
								setMethod.invoke(tObject, new BigDecimal(numericCell));
							}
						}
					}
				}
				dist.add(tObject);
			}
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		return dist;
	}
    /**
     * 
     * @param request
     * @param response
     * @param listUser导出数据集
     * @param pojoClass 导出数据的实体
     * @param title 导出文件名
     * @throws Exception
     */
    public static void exportExcel(HttpServletRequest request,HttpServletResponse response, Collection<?> listUser,Class<?> pojoClass,String title) throws Exception {
    	response.setContentType("application/vnd.ms-excel;charset=utf-8");
    	String fileName = title+".xls";
    	
    	//update-begin-Alex----Date:20180910----for:解决IE浏览器导出时名称乱码问题---
    	String finalFileName = null;
    	String userAgent = request.getHeader("user-agent");

    	if (userAgent != null && userAgent.indexOf("MSIE") >= 0 || userAgent.indexOf("Trident") >= 0 || userAgent.indexOf("Edge") >= 0) {
    		//IE（Trident）内核
    		finalFileName =URLEncoder.encode(fileName,"UTF-8");
    	} else if(userAgent != null && userAgent.indexOf("chrome") >= 0 || userAgent.indexOf("safari") >= 0 || userAgent.indexOf("Firefox") >= 0) {
    		//谷歌、火狐等浏览器
    		finalFileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
    	}else{
    		finalFileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
    	}
    	//这里设置一下让浏览器弹出下载提示框，而不是直接在浏览器中打开
    	response.setHeader("Content-Disposition", "attachment; filename="+ finalFileName);
    	//update-end-Alex----Date:20180910----for:解决IE浏览器导出时名称乱码问题---
    	File file = new File(new Date(0).getTime()+".xls");
    	OutputStream outputStream = new FileOutputStream(file);
    	ExcelUtil.exportExcel(title,pojoClass, listUser, outputStream);
    	InputStream is = new BufferedInputStream(new FileInputStream(file.getPath()));
    	file.delete();
    	outputStream.close();
    	OutputStream os = response.getOutputStream();
    	byte[] b = new byte[2048];
    	int length;
    	while ((length = is.read(b)) > 0) {
    		os.write(b, 0, length);
    	}
    	os.close();
    	is.close();
	}
    
}
